package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.passport.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminLoginDTO;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 处理管理员数据的业务实现类
 *
 * @author wys
 * @version 0.0.1
 *
 */

@Slf4j
@Service
public class AdminServiceImpl implements IAdminService {

    public AdminServiceImpl() {
        log.debug("创建业务实现类: AdminServiceImpl");
    }

    @Autowired
    AdminMapper adminMapper;
    @Autowired
    AdminRoleMapper adminRoleMapper;
    @Autowired
    PasswordEncoder passwordEncoder;
    @Autowired
    AuthenticationManager authenticationManager;

    //获取yml文件里的自定义配置值
    @Value("${csmall.jwt.secret-key}")
    String secretKey;
    @Value("${csmall.jwt.duration-in-minute}")
    long durationInMinute;


    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理[管理员登录]的业务, 参数:{}", adminLoginDTO);
        // 调用AuthenticationManager对象的authenticate()方法处理认证
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                adminLoginDTO.getUsername(), adminLoginDTO.getPassword());
          Authentication authenticateResult= authenticationManager.authenticate(authentication);  //返回认证结果
        log.debug("执行认证成功, AuthenticationManager返回: {}", authenticateResult);
        Object principal = authenticateResult.getPrincipal();
        log.debug("认证结果中的Principal数据类型: {}", principal.getClass().getName());
        log.debug("认证结果中的Principal数据: {}", principal);
        AdminDetails adminDetails = (AdminDetails) principal;

        log.debug("准备生成JWT数据");
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", adminDetails.getId());  //向JWT中封装id
        claims.put("username", adminDetails.getUsername());  //向JWT中封装username
        claims.put("authorities", JSON.toJSONString(adminDetails.getAuthorities())); //向JWT中封装权限

        Date expirationDate = new Date(System.currentTimeMillis() + durationInMinute * 60 * 1000);
        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                .setClaims(claims)
                .setExpiration(expirationDate)  //设置过期时间
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("返回JWT数据: {}", jwt);
        return jwt;


    }





    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理[添加管理员]的业务, 参数: []", adminAddNewDTO);

        log.debug("即将检查选择的角色是否合法....");
        Long[] roleIds = adminAddNewDTO.getRoleIds();
        for (int i = 0; i < roleIds.length; i++) {
            if (roleIds[i] == 1) {
                String message = "添加管理员失败，非法访问！";
                log.debug(message);
                throw new ServiceException(ServiceCode.ERR_INSERT, message);
            }
        }



        log.debug("即将检查用户名是否被占用......");
            String username = adminAddNewDTO.getUsername();
        int countByUser = adminMapper.countByUsername(username);
        if (countByUser != 0){
            String message = "添加管理员失败，用户名【" + username + "】已经被占用！";
            log.debug(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT,message);
        }

        log.debug("即将检查手机号码是否被占用......");

        String phone = adminAddNewDTO.getPhone();
        int countByPhone = adminMapper.countByPhone(phone);
        if(countByPhone != 0){
            String message = "添加管理员失败，手机号码【" + phone + "】已经被占用！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        log.debug("即将检查电子邮箱是否被占用......");

        String email = adminAddNewDTO.getPhone();
        int countByEmail = adminMapper.countByEmail(phone);
        if(countByEmail != 0){
            String message = "添加管理员失败，电子邮箱【" + email + "】已经被占用！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }




        //创建Admin对象
        Admin admin = new Admin();
        // 通过BeanUtils.copyProperties()方法将参数对象的各属性值复制到Admin对象中
        BeanUtils.copyProperties(adminAddNewDTO,admin);
        // 从Admin对象中取出密码, 进行加密处理, 并将密文封装回Admin对象中
        String rawPassword = admin.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodedPassword);

        // 补全Admin对象中的属性值: loginCount >>> 0
        admin.setLoginCount(0); //设置登录次数,方便后续计算
        // 调用adminMapper的insert()方法插入数据
        log.debug("即将插入管理员数据，参数：{}", admin);
        int rows = adminMapper.insert(admin);
        //判断插入数据的结果是否复合预期
        if(rows != 1){
            String message = "添加管理员失败, 服务器忙, 请稍后再次尝试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        //调用adminRoleMapper的insertBatch()方法插入关联数据
        List<AdminRole> adminRoleList = new ArrayList<>();
        for(int i = 0; i < roleIds.length; i++){
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(admin.getId());
            adminRole.setRoleId(roleIds[i]);
            adminRoleList.add(adminRole);
        }
        rows = adminRoleMapper.insertBatch(adminRoleList);
        //判断插入数据的结果是否复合预期
        if(rows != roleIds.length){
            String message = "添加管理员失败, 服务器忙, 请稍后再次尝试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

    }



    @Override
    public void deleteById(Long id) {
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if(queryResult == null){
            String message = "删除管理员失败, 尝试访问的数据不存在!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        //执行删除管理员
        int rows = adminMapper.deleteById(id);
        //判断删除数据的结果是否复合预期
        if(rows != 1){
            String message = "删除管理员失败, 服务器忙, 请稍后再次尝试!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        // 执行删除此管理员与角色的关联数据
        rows = adminRoleMapper.deleteByAdminId(id);
        if (rows < 1) {
            String message = "删除管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }
    }




    @Override
    public void setEnable(Long id) {
        updateEnableById(id,1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id,0);
    }

    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理[查询管理员列表]的业务");
        //调用Mapper查询管理员列表
        List<AdminListItemVO> list = adminMapper.list();
        // list.remove(0);
        //  将管理员列表中id=1的管理员数据移除 (隐藏系统管理员)
        Iterator<AdminListItemVO> iterator = list.iterator();
        while(iterator.hasNext()){
            AdminListItemVO item = iterator.next();
            if(item.getId() == 1){
                iterator.remove();
                break;
            }

        }

       // 返回移除id为1的系统管理员的管理员列表
        return list;
    }

    //用于检查数据的安全性
    private void updateEnableById(Long id, Integer enable) {
        String[] tips = {"禁用", "启用"};
        log.debug("开始处理【{}管理员】的业务，参数：{}", tips[enable], id);

        // 判断参数id是否为1
        if (id == 1) {
            String message = tips[enable] + "管理员失败，尝试访问的数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 检查尝试访问的数据是否存在
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if (queryResult == null) {
            String message = tips[enable] + "管理员失败，尝试访问的数据不存在！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 判断状态是否冲突（当前已经是目标状态）
        if (queryResult.getEnable() == enable) {
            String message = tips[enable] + "管理员失败，管理员账号已经处于" + tips[enable] + "状态！";
            log.debug(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 准备执行更新
        Admin admin = new Admin();
        admin.setId(id);
        admin.setEnable(enable);
        int rows = adminMapper.updateById(admin);
        if (rows != 1) {
            String message = tips[enable] + "管理员失败，服务器忙，请稍后再次尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

}
